/**
 * @license
 * Copyright 2021 Du Tian Wei
 * SPDX-License-Identifier: Apache-2.0
 */

// <script src="editor/js/index.js"></script>
(function () {
    const CONFIG_PATH = './config/project.json';
    const TEMPLATE_CONFIG_PATH = './config/templates.json';
    const SRC_PATH = "/assets/src/";
    const SRC_POSTFIX = ".xs";
    const LIB_PATH = "/assets/lib/";
    const LIB_POSTFIX = ".xl";
    const DATA_PATH = "/assets/data/";
    const DATA_POSTFIX = ".xlsx";
    const MAIN_XE_PATH = "/assets/exe/main.xe";
    const MAIN_XE_HASH_PATH = "/assets/exe/main.hash";

    let template;
    let config = { projects: [] };
    let module = {
        config,
        project: null
    };
    let script = document.createElement('script');
    script.src = 'editor/3rd/md5.min.js';
    script.type = 'text/javascript';
    script.onerror = (e) => {
        console.error(e);
    }
    document.head.appendChild(script);
    function checkErr(err) {
        if (err) {
            console.error(err);
            throw err;
        }
    }

    $.ajax({
        url: 'editor/htmls/project.html',
        dataType: 'text',
        async: false,
        success(data, status, xhr) {
            template = data;
        }
    });
    function loadConfig(path, callback) {
        NativeInterface.ensureFile(path, (err) => {
            checkErr(err);
            NativeInterface.readTextFile(path, (err, data) => {
                callback(err, data);
            });
        });
    }
    loadConfig(CONFIG_PATH, (err, data) => {
        checkErr(err);
        if (data && data.length > 0) {
            module.config = JSON.parse(data);
        }
    });
    loadConfig(TEMPLATE_CONFIG_PATH, (err, data) => {
        checkErr(err);
        if (data && data.length > 0) {
            module.templates = JSON.parse(data);
        }
    });
    function newProjectTemplate() {
        return {
            name: '',
            path: '',
            template: ''
        };
    }
    Vue.component('project-ui', {
        data() {
            return {
                showCreateUI: false,
                module,
                newProjectInfo: newProjectTemplate(),
                ruleCustom: {
                    name(value, callback) {
                        if (!value) {
                            callback(new Error("输入项目名称"));
                        } else if (value.length == 0) {
                            callback(new Error("输入项目名称"));
                        } else {
                            callback();
                        }
                    },
                    template(value, callback) {
                        if (!value) {
                            callback("请选择模板");
                            return;
                        }
                        let template = module.templates.find(t => t.name == value);
                        if (template) {
                            callback();
                        } else {
                            callback("请选择模板");
                        }
                    },
                    path(value, callback) {
                        if (!value) {
                            callback("请选择位置");
                            return;
                        }
                        NativeInterface.pathExists(value, (err, exists) => {
                            if (err) {
                                callback(err);
                            } else if (!exists) {
                                callback('位置不存在');
                            } else {
                                callback();
                            }
                        });
                    }
                }
            };
        },
        methods: {
            showError(err) {
                console.log(err);
                this.$Modal.error({
                    "title": "错误",
                    "content": err.message || err,
                });
            },
            createProjectDir(info) {
                showOverallLoading();
                let self = this;
                let template = module.templates.find(t => t.name == info.template);
                NativeInterface.copy(template.path, info.path, (err) => {
                    if (err) {
                        self.showError(err);
                        hideOverallLoading();
                        return;
                    } else {
                        self.module.config.projects.unshift(info);
                        NativeInterface.writeTextFile(info.path + "/project.json",
                            JSON.stringify({ "name": info.name, "SN": Ublockly.Utils.makeSN() }),
                            (err) => {
                                if (err) {
                                    self.showError(e);
                                    hideOverallLoading();
                                    return;
                                } else {
                                    this.writeToConfig();
                                }
                            });
                    }
                });
            },
            writeToConfig() {
                NativeInterface.writeTextFile(CONFIG_PATH, JSON.stringify(this.module.config), (err) => {
                    if (err) {
                        this.showError(e);
                        hideOverallLoading();
                        return;
                    } else {
                        this.showCreateUI = false;
                        this.newProjectInfo = newProjectTemplate();
                        hideOverallLoading();
                    }
                });
            },
            AddProject() {
                let opt = {
                    title: '选择路径',
                    properties: ['openDirectory', 'dontAddToRecent']
                };
                NativeInterface.showOpenDialog(opt, (result) => {
                    if (result.canceled) {
                        return;
                    }
                    let paths = result.filePaths;
                    if (paths.length > 0) {
                        path = paths[0];
                        NativeInterface.readTextFile(path + "/project.json", (err, txt) => {
                            if (err) {
                                console.error(err);
                                alert(err.message)
                                return;
                            }
                            let projectInfo = JSON.parse(txt);
                            projectInfo.path = path;
                            this.module.config.projects.unshift(projectInfo);
                            this.writeToConfig();
                        });
                    }
                });
            },
            createProject() {
                this.showCreateUI = true;
                this.newProjectInfo = newProjectTemplate();
            },
            selectDir(proj) {
                let opt = {
                    title: '选择路径',
                    defaultPath: proj.path,
                    properties: ['openDirectory', 'createDirectory', 'promptToCreate', 'dontAddToRecent']
                };
                NativeInterface.showOpenDialog(opt, (result) => {
                    if (result.canceled) {
                        return;
                    }
                    let paths = result.filePaths;
                    if (paths.length > 0) {
                        proj.path = paths[0];
                    }
                });
            },
            removeProject(p) {
                this.$Modal.confirm({
                    title: '移除项目',
                    content: `<p>从列表中移除项目 ${p.name}</p>`,
                    onOk() {
                        let i = module.config.projects.indexOf(p);
                        module.config.projects.splice(i, 1);
                        NativeInterface.writeTextFile(CONFIG_PATH, JSON.stringify(self.module.config), (err) => {
                            if (err) {
                                self.showError(e);
                                return;
                            }
                        });
                    }
                });
            },
            openProject(p) {
                // let loading = document.getElementById('system-loading');
                // loading.style.display = 'block';
                NativeInterface.openProject(p);
                this.project = p;
                showOverallLoading();
                this.loadProject(p, (err) => {
                    hideOverallLoading();
                    if (!err) {
                        this.$root.showEditor = true;
                        this.$root.showProjectWindow = false;
                        this.showCreateUI = false;
                        this.$root.showProjectWindow = false;
                        document.head.title = p.name + ":" + document.head.title;
                    } else {
                        this.showError(err);
                    }
                });
            },
            runProject() {
                this.$root.tabs.forEach(tab => {
                    let t = tab.target;
                    if (t && t.saveCode) {
                        t.saveCode();
                    }
                });
                Ublockly.exportExePackage((err) => {
                    if (err) {
                        this.showError(err);
                    } else {
                        NativeInterface.runProject(this.project);
                    }
                });
            },
            loadProject(p) {
                let self = this;
                function loadSrc(cb) {
                    let srcPath = p.path + SRC_PATH;
                    NativeInterface.ensureDir(srcPath, () => {
                        NativeInterface.readTextFilesInDir(srcPath, {
                            "postfix": [SRC_POSTFIX]
                        }, (err, strArr) => {
                            if (err) {
                                err.forEach(e => {
                                    self.showError(e);
                                });
                            }
                            if (strArr) {
                                let jsonArr = [];
                                strArr.forEach(str => {
                                    let json = JSON.parse(str);
                                    if (json.type === 'src' || json.type === 'lib') {
                                        //TODO： check json schema by ajv
                                        jsonArr.push(json);
                                    }
                                });

                                try {
                                    Ublockly.BlocklyParser.addFiles(jsonArr);
                                } catch (e) {
                                    self.showError(e);
                                }
                                cb();
                            }
                        });
                    });
                }
                function loadLib(cb) {
                    let srcPath = p.path + LIB_PATH;
                    NativeInterface.ensureDir(srcPath, () => {
                        NativeInterface.readTextFilesInDir(srcPath, {
                            "postfix": [LIB_POSTFIX]
                        }, (err, strArr) => {
                            if (err) {
                                err.forEach(e => {
                                    self.showError(e);
                                });
                            }
                            if (strArr) {
                                let jsonArr = [];
                                strArr.forEach(str => {
                                    let json = JSON.parse(str);
                                    if (json.type === 'src' || json.type === 'lib') {
                                        //TODO： check json schema by ajv
                                        jsonArr.push(json);
                                    }
                                });

                                try {
                                    Ublockly.BlocklyParser.addFiles(jsonArr);
                                } catch (e) {
                                    self.showError(e);
                                }
                                cb();
                            }
                        });
                    });
                }
                // function loadData(cb) {
                //     let dataPath = p.path + DATA_PATH;
                //     NativeInterface.ensureDir(dataPath, () => {
                //         NativeInterface.readBinFilesInDir(dataPath, {
                //             "postfix": [DATA_POSTFIX]
                //         }, (err, binArr) => {
                //             if (err) {
                //                 err.forEach(e => {
                //                     self.showError(e);
                //                 });
                //             }
                //             if (binArr) {
                //                 try {
                //                     Ublockly.DataImporter.importExcel(binArr);
                //                     Ublockly.exportExePackage();
                //                 } catch (e) {
                //                     self.showError(e);
                //                 }
                //             }
                //             cb();
                //         });
                //     });
                // }
                // loadData(() => {
                    loadLib(() => {
                        var jsarr = [
                            "/project/" + p.name + "/assets/env/i18n_zh.js",
                            "/project/" + p.name + "/assets/env/nativeEvent.js",
                            "/project/" + p.name + "/assets/env/native.js"
                        ];
                        var xmlpath = "/project/" + p.name + "/assets/env/nativeBlocks.xml";
                        // 加载本地 国际化，存根文件，配置文件
                        Ublockly.loadNativeInfo(jsarr, xmlpath, () => {
                            loadSrc(() => {
                                // load excel
                                let dataroot = p.path + "/assets/data/";
                                NativeInterface.listFilesInDir(dataroot, null, (errs, files) => {
                                    if (errs) {
                                        console.error(errors);
                                    }
                                    if (files) {
                                        files.forEach(file => {
                                            let filename = file.substr(dataroot.length);
                                            if(filename.startsWith(".")){
                                                return;
                                            }
                                            if(filename.startsWith("~")){
                                                return;
                                            }
                                            NativeInterface.readBinFile(file, (err, bin) => {
                                                if (err) {
                                                    errs.push(err);
                                                } else if (bin) {
                                                    let info = { name: filename, content: bin.buffer };
                                                    Ublockly.DataImporter.importExcel([info]);
                                                }
                                            });
                                        });
                                    }
                                });
                                self.$root.showEditor = true;
                                self.$root.showProjectWindow = false;
                                self.showCreateUI = false;
                                hideOverallLoading();
                            });
                        });
                    });
                // });
            },
            handleSubmit() {
                let self = this;
                let checking = ['name', 'template', 'path'];
                function check(e) {
                    if (e) {
                        self.showError(e);
                    } else {
                        if (checking.length == 0) {
                            self.createProjectDir(self.newProjectInfo);
                            return;
                        }
                        let field = checking.shift();
                        self.ruleCustom[field](self.newProjectInfo[field], check);
                    }
                }
                check();
            },
            handleReset() {
                this.newProjectInfo = newProjectTemplate();
                this.showCreateUI = false;
            },
            saveProject() {
                this.saveFiles(Ublockly.BlocklyParser.loadedFiles.srcs);
            },
            saveFiles(files) {
                let self = this;
                files.forEach(file => {
                    self.saveFile(file);
                });
            },
            saveFile(file) {
                let path;
                if (file.type == 'src') {
                    let sn = file.SN;
                    if (!sn) {
                        sn = Ublockly.Utils.makeSN();
                        file.SN = sn;
                    }
                    path = this.project.path + SRC_PATH + sn + SRC_POSTFIX;
                } else if (file.type == 'lib') {
                    path = this.project.path + LIB_PATH + file.name + LIB_POSTFIX
                } else {
                    this.showError(new Error('未知文件类型' + file.type + " " + file.name));
                }
                Ublockly.serializeSrc(file, (err, sfile) => {
                    NativeInterface.writeTextFile(path, sfile, (err) => {
                        if (err) {
                            this.showError(err);
                        }
                    });
                });
            },
            removeFiles(files) {
                let self = this;
                files.forEach(file => {
                    this.removeFile(file);
                });
            },
            removeFile(file) {
                if (file.type == 'src') {
                    let sn = file.SN;
                    if (sn) {
                        NativeInterface.removeFile(this.project.path + SRC_PATH + sn + SRC_POSTFIX, (err) => {
                            if (err) {
                                this.showError(err);
                            }
                        });
                    }
                } else if (file.type == 'lib') {
                    NativeInterface.removeFile(this.project.path + LIB_PATH + file.name + LIB_POSTFIX, (err) => {
                        if (err) {
                            this.showError(err);
                        }
                    });
                }
            }
        },
        created() {
            let self = this;
            this.$root.showEditor = false;
            this.$root.showProjectWindow = true;
            this.$root.runProject = () => {
                this.runProject();
            };
            this.$root.importData = function () {
                let project = self.project;
                let root = project.path + "/assets/data/";
                NativeInterface.ensureDir(root, (err) => {
                    if (err) {
                        alert(err.message);
                        return;
                    }
                    FileInterface.loadExcel((arrayBufferArray) => {
                        // [{name:"",content:ArrayBuffer}]
                        arrayBufferArray.forEach(file => {
                            let buf = file.content;
                            let name = file.name;
                            let path = root + name;
                            NativeInterface.pathExists(path, (err, r) => {
                                if (!r) {
                                    NativeInterface.writeBinFile(path, new Uint8Array(buf), (err) => {
                                        if (err) {
                                            console.error(err);
                                        } else {
                                            console.log(name + "write to excel:" + path);
                                            Ublockly.DataImporter.importExcel([file]);
                                        }
                                    });
                                } else {
                                    self.$root.prompt("文件已存在", "是否覆盖:" + name + " ？", (b) => {
                                        if (b) {
                                            NativeInterface.writeBinFile(path, new Uint8Array(buf), (err) => {
                                                if (err) {
                                                    console.error(err);
                                                } else {
                                                    console.log(name + "write to excel:" + path);
                                                    Ublockly.DataImporter.importExcel([file]);
                                                }
                                            });
                                        }
                                    });
                                }
                            });
                        });
                    });
                });
            };
            let timeout = -1;
            Ublockly.wsBuildCbs.push(function (ws) {
                ws.addChangeListener(function (e) {
                    let time = 5000;
                    if (e.recordUndo) {
                        time = 15000
                    }
                    if (timeout > 0) {
                        clearTimeout(timeout);
                    }
                    timeout = setTimeout(() => {
                        self.saveFile(ws._ublockly_env._ublockly_src);
                    }, time);

                });
            });
            Ublockly.BlocklyParser.addFilesAddedListener(files => {
                self.saveFiles(files);
            });
            Ublockly.BlocklyParser.addFilesRemovedListener(files => {
                self.removeFiles(files);
            });
            Ublockly.Linker.onFinished((e, r) => {
                self.saveProject();
                if (!e && r && this.project && this.project.path) {
                    let uint8arr = new Uint8Array(r);
                    let xepath = this.project.path + MAIN_XE_PATH;
                    NativeInterface.ensureFile(xepath, () => {
                        NativeInterface.writeBinFile(xepath, uint8arr, (err) => {
                            if (err) {
                                this.showError(err);
                                return;
                            }
                            let hash = md5(uint8arr);
                            NativeInterface.writeTextFile(this.project.path + MAIN_XE_HASH_PATH, hash, (err) => {
                                if (err) {
                                    this.showError(err);
                                }
                            });
                        });
                    });
                }
            });
        }, template
    });

})();